﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading;
using BLL.Workflows;
using Common;
using DAL.ETL;
using DO.ETL;
using DO.Workflows;

namespace BLL.ETL
{
    public class CitationParserWorker:WorkerBase 
    {
        #region Overrides of WorkerBase

        private CitationParserInstruction _Instruction;
        /// <summary>
        /// allow instruction to be changed at runtime
        /// </summary>
        public override InstructionBase Instruction
        {
            get
            {
                return _Instruction;
            }
            set
            {
                _Instruction = (CitationParserInstruction) value;
            }
        }

        private CitationParserOutput _Output;
        /// <summary>
        /// output
        /// </summary>
        public override ResultBase Output
        {
            get
            {
                return _Output;
            }
        }

        /// <summary>
        /// allow worker to be created based on component type
        /// </summary>
        public override Type ComponentType
        {
            get
            {
                return typeof (CitationParserComponent);
            }
        }

        /// <summary>
        /// allow instruction to be instantiated
        /// </summary>
        public override Type InstructionType
        {
            get
            {
                return typeof (CitationParserInstruction);
            }
        }

        public override event WorkerFinished WorkerFinishedEvent;
        public override event WorkerHasError WorkerErredEvent;
        public override event WorkerStatusChanged WorkerStatusChangedEvent;
        protected override void StartWork()
        {
            try
            {
                string connStr = ConfigurationManager.ConnectionStrings[this._Instruction.ConnName].ConnectionString;
                int totalRecordCount = DbUtil.GetTableRecordCount(
                    DataProviderType.MSSQL, connStr, this._Instruction.SQL);
                IDataReader reader = CitationParserDALC.GetCitationText(
                    this._Instruction.ConnName, this._Instruction.ConnName);
                if(reader==null)
                    throw new Exception("Unable to retrieve citation source data");

                int citationCount = 0;
                int recordCount = 0;
                while(reader.Read())
                {
                    int key = int.Parse(reader[this._Instruction.KeyField].ToString());
                    if(reader[this._Instruction.CitationField]!=DBNull.Value)
                    {
                        string citationText = reader[this._Instruction.CitationField].ToString();
                        Citation result;
                        bool canParse = this.TryParseCitation(citationText, out result);
                        if(canParse)
                        {
                            CitationParserDALC.SaveParserResult(
                                this._Instruction.ConnName,
                                this._Instruction.SrcKeyField, key,
                                this._Instruction.PubTimeField, result.PubDate,
                                this._Instruction.JournalNameField,result.Journal,
                                this._Instruction.BookTitleMeetingField, result.Title,
                                this._Instruction.TitleField,result.Title,
                                this._Instruction.AuthorsField,result.Authors,
                                this._Instruction.VolumeField,result.Volume,
                                this._Instruction.IssueField,result.Issue,
                                this._Instruction.PageField,result.Pages);
                            citationCount++;
                        }
                    }
                    recordCount++;

                    if(recordCount % 100==0 && this.WorkerStatusChangedEvent!=null)
                    {
                        string msg = string.Format(
                            "Processed {0} of {1} records, {2} citations found",
                            recordCount, totalRecordCount, citationCount);
                        int pct = recordCount * 100 / totalRecordCount;
                        this.WorkerStatusChangedEvent(
                            this.JobTicket, this.GetType(), 
                            this._Instruction, this.WorkflowName,
                            this.ComponentName, msg, pct);
                    }
                }

                this._Output=new CitationParserOutput(this._Instruction.ComponentID, this.JobTicket, recordCount, citationCount);
                if (this.WorkerFinishedEvent != null)
                    this.WorkerFinishedEvent(this.JobTicket, this.GetType(), this._Instruction, this._Output);
                reader.Close();
            }
            catch(Exception ex)
            {
                if (this.WorkerErredEvent != null)
                    this.WorkerErredEvent(this.JobTicket, this.GetType(), this.Instruction, ex.ToString(), true);
            }
        }

        private bool TryParseCitation(
            string citationText, out Citation result)
        {
            result=new Citation();
            try
            {
                RuleBasedCitationExtractor worker=new RuleBasedCitationExtractor();
                result = worker.Parse(citationText);
                return true;
            }
            catch (Exception ex)
            {
                if (this.WorkerErredEvent != null)
                    this.WorkerErredEvent(this.JobTicket, this.GetType(), this._Instruction, ex.ToString(), false);
            }
            return false;
        }

        #endregion
    }
}
